﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Interop;
using System.Runtime.InteropServices;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Diagnostics;
using PM.Controls.Common;

namespace PM.Controls
{
    [TemplatePart(Name = "PART_CloseButton", Type = typeof(Button))]
    [TemplatePart(Name = "PART_MinimizeButton", Type = typeof(Button))]
    [TemplatePart(Name = "PART_MaximizeButton", Type = typeof(Button))]
    [TemplatePart(Name = "PART_NResizer", Type = typeof(Path))]
    [TemplatePart(Name = "PART_SResizer", Type = typeof(Path))]
    [TemplatePart(Name = "PART_EResizer", Type = typeof(Path))]
    [TemplatePart(Name = "PART_WResizer", Type = typeof(Path))]
    [TemplatePart(Name = "PART_NWResizer", Type = typeof(Rectangle))]
    [TemplatePart(Name = "PART_NEResizer", Type = typeof(Rectangle))]
    [TemplatePart(Name = "PART_SWResizer", Type = typeof(Rectangle))]
    [TemplatePart(Name = "PART_SEResizer", Type = typeof(Rectangle))]
    [TemplatePart(Name = "PART_TitleBar", Type = typeof(Panel))]
    public class PMWindow : System.Windows.Window
    {
        private WindowInteropHelper _interopHelper;

        static PMWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(PMWindow),
                                                     new FrameworkPropertyMetadata(
                                                        typeof(PMWindow)));
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _interopHelper = new WindowInteropHelper(this);
            AttachToVisualTree();
            this.Loaded += (o, e) =>
            {
                Storyboard s = Tools.PerformInEffect(this);
                s.Begin();
            };
        }

        private void AttachToVisualTree()
        {
            // Close Button
            Button closeButton = GetChildControl<Button>("PART_CloseButton");
            if (closeButton != null)
            {
                closeButton.Click += OnCloseButtonClick;
            }

            // Minimize Button
            Button minimizeButton = GetChildControl<Button>("PART_MinimizeButton");
            if (minimizeButton != null)
            {
                minimizeButton.Click += OnMinimizeButtonClick;
            }

            // Maximize Button
            Button maximizeButton = GetChildControl<Button>("PART_MaximizeButton");
            if (maximizeButton != null)
            {
                maximizeButton.Click += OnMaximizeButtonClick;
            }

            // Resizers
            if (ResizeMode != ResizeMode.NoResize)
            {
                Path sResizer = GetChildControl<Path>("PART_SResizer");
                if (sResizer != null)
                {
                    sResizer.MouseDown += OnSizeSouth;
                }

                Path nResizer = GetChildControl<Path>("PART_NResizer");
                if (nResizer != null)
                {
                    nResizer.MouseDown += OnSizeNorth;
                }

                Path eResizer = GetChildControl<Path>("PART_EResizer");
                if (eResizer != null)
                {
                    eResizer.MouseDown += OnSizeEast;
                }

                Path wResizer = GetChildControl<Path>("PART_WResizer");
                if (wResizer != null)
                {
                    wResizer.MouseDown += OnSizeWest;
                }

                Rectangle seResizer = GetChildControl<Rectangle>("PART_SEResizer");
                if (seResizer != null)
                {
                    seResizer.MouseDown += OnSizeSouthEast;
                }

                Rectangle swResizer = GetChildControl<Rectangle>("PART_SWResizer");
                if (swResizer != null)
                {
                    swResizer.MouseDown += OnSizeSouthWest;
                }

                Rectangle neResizer = GetChildControl<Rectangle>("PART_NEResizer");
                if (neResizer != null)
                {
                    neResizer.MouseDown += OnSizeNorthEast;
                }

                Rectangle nwResizer = GetChildControl<Rectangle>("PART_NWResizer");
                if (nwResizer != null)
                {
                    nwResizer.MouseDown += OnSizeNorthWest;
                }
            }

            // Title Bar
            Panel titleBar = GetChildControl<Panel>("PART_TitleBar");
            if (titleBar != null)
            {
                titleBar.MouseLeftButtonDown += OnTitleBarMouseDown;
            }
        }

        private void OnMaximizeButtonClick(object sender, RoutedEventArgs e)
        {
            ToggleMaximize();
        }

        private void ToggleMaximize()
        {

            Border windowBorder = GetChildControl<Border>("PART_WindowBorder");
            if (this.WindowState == WindowState.Maximized)
            {
                this.WindowState = WindowState.Normal;
                windowBorder.Margin = new Thickness(10);
            }
            else
            {
                this.WindowState = WindowState.Maximized;
                windowBorder.Margin = new Thickness(0, 5, 0, 0);
            }
        }

        private void OnTitleBarMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (ResizeMode != ResizeMode.NoResize && e.ClickCount == 2)
            {
                ToggleMaximize();
                return;
            }
            this.DragMove();
        }

        protected T GetChildControl<T>(string ctrlName) where T : DependencyObject
        {
            T ctrl = GetTemplateChild(ctrlName) as T;
            return ctrl;
        }

        protected void MoveWindow(Rect rect)
        {
            MoveWindow(_interopHelper.Handle, (int)rect.Left,
                       (int)rect.Top, (int)rect.Width, (int)rect.Height, false);
        }

        private void OnCloseButtonClick(object sender, RoutedEventArgs e)
        {
            CloseWindow();
        }

        private void OnMinimizeButtonClick(object sender, RoutedEventArgs e)
        {
            WindowState = WindowState.Minimized;
        }
        public void CloseWindow()
        {
            Storyboard s = Tools.PerformOutEffect(this);
            s.Completed += (o, e) =>
            {
                Close();
            };
            s.Begin();
        }
        #region Sizing Event Handlers

        private void OnSizeSouth(object sender, MouseButtonEventArgs e)
        {
            DragSize(_interopHelper.Handle, SizingAction.South);
        }

        private void OnSizeNorth(object sender, MouseButtonEventArgs e)
        {
            DragSize(_interopHelper.Handle, SizingAction.North);
        }

        private void OnSizeEast(object sender, MouseButtonEventArgs e)
        {
            DragSize(_interopHelper.Handle, SizingAction.East);
        }

        private void OnSizeWest(object sender, MouseButtonEventArgs e)
        {
            DragSize(_interopHelper.Handle, SizingAction.West);
        }

        private void OnSizeNorthWest(object sender, MouseButtonEventArgs e)
        {
            DragSize(_interopHelper.Handle, SizingAction.NorthWest);
        }

        private void OnSizeNorthEast(object sender, MouseButtonEventArgs e)
        {
            DragSize(_interopHelper.Handle, SizingAction.NorthEast);
        }

        private void OnSizeSouthEast(object sender, MouseButtonEventArgs e)
        {
            DragSize(_interopHelper.Handle, SizingAction.SouthEast);
        }

        private void OnSizeSouthWest(object sender, MouseButtonEventArgs e)
        {
            DragSize(_interopHelper.Handle, SizingAction.SouthWest);
        }

        #endregion

        #region P/Invoke and Helper Method

        public enum SizingAction
        {
            North = 3,
            South = 6,
            East = 2,
            West = 1,
            NorthEast = 5,
            NorthWest = 4,
            SouthEast = 8,
            SouthWest = 7
        }

        private const int SC_SIZE = 0xF000;
        private const int WM_SYSCOMMAND = 0x112;

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam,
                                                 IntPtr lParam);

        [DllImport("user32")]
        private static extern Boolean MoveWindow(
            IntPtr hWnd,
            Int32 x, Int32 y,
            Int32 nWidth, Int32 nHeight, Boolean bRepaint);

        private void DragSize(IntPtr handle, SizingAction sizingAction)
        {
            if (Mouse.LeftButton == MouseButtonState.Pressed)
            {
                SendMessage(handle, WM_SYSCOMMAND, (IntPtr)(SC_SIZE + sizingAction), IntPtr.Zero);
                SendMessage(handle, 514, IntPtr.Zero, IntPtr.Zero);
            }
        }

        #endregion
    }
}
